package com.example.gongzhong1.utils;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
* @Description:    从request中获取xml格式的数据并解析为map集合
* @Author:         xiayuxuanmin
* @CreateDate:     2019/6/4 15:07
* @Version:        1.0
*/
public class MessageUtil {

    public static final String RESP_MESSAGE_TYPE_TEXT = "text";

    /**
     * 解析微信请求的xml格式的数据,返回以参数名为key,参数值为vlaue的map
     * @param request
     * @return
     * @throws Exception
     */
    public static Map<String,String> parseXml(HttpServletRequest request) throws Exception{
        //将解析结果放入到该map中
        Map<String,String>  requestMap = new HashMap<>();
        //从request中取得输入流
        ServletInputStream inputStream = request.getInputStream();

        //读取输入流
        SAXReader reader = new SAXReader();
        Document doucument = reader.read(inputStream);
        //获取根元素
        Element root = doucument.getRootElement();
        //得到根元素的所有子节点
        List<Element> elements = root.elements();
        //遍历所有子节点,获取信息内容
        for(Element element:elements){
            requestMap.put(element.getName(),element.getText());
        }
        //释放资源
        inputStream.close();
        inputStream = null;

        return requestMap;
    }

    /**
     * 拓展xstream,使得支持CDATA块
     */
    private static XStream xstream = new XStream(new XppDriver() {
        public HierarchicalStreamWriter createWriter(Writer out) {
            return new PrettyPrintWriter(out) {
                // 对那些xml节点的转换增加CDATA标记   true增加  false反之
                boolean cdata = false;

                /**
                 *
                 * @param name  xml的元素节点如果不等于<xml>,例如为<xml1>,那么会将元素节点的首字母大写,变为:<Xml1>
                 * @param clazz
                 */
                @SuppressWarnings("unchecked")
                public void startNode(String name, Class clazz) {
                    if(!name.equals("xml")){
                        char[] arr = name.toCharArray();
                        if (arr[0] >= 'a' && arr[0] <= 'z') {
                            //arr[0] -= 'a' - 'A';
                            //ASCII码，大写字母和小写字符之间数值上差32
                            arr[0] = (char) ((int) arr[0] - 32);
                        }
                        name = new String(arr);
                    }
                    super.startNode(name, clazz);
                }

                /**
                 * 给属性值不为浮点型或者整形的属性加上<![CDATA["+属性值+"]]>的标签
                 * @param text
                 */
                @Override
                public void setValue(String text) {
                    if(text!=null && !"".equals(text)){
                        //浮点型判断
                        Pattern patternInt = Pattern.compile("[0-9]*(\\.?)[0-9]*");
                        //整型判断
                        Pattern patternFloat = Pattern.compile("[0-9]+");
                        //如果是整数或浮点数 就不要加[CDATA[]了
                        if(patternInt.matcher(text).matches() || patternFloat.matcher(text).matches()){
                            cdata = false;
                        }else{
                            cdata = true;
                        }
                    }
                    super.setValue(text);
                }

                /**
                 * 在xml节点中写入节点内容
                 * @param writer
                 * @param text
                 */
                protected void writeText(QuickWriter writer, String text) {
                    /*
                        if (cdata) {
                            text = "<![CDATA["+text+"]]>";
                        }
                        super.writeText(writer, text);
                    */
                    if (cdata) {
                        writer.write("<![CDATA[");
                        writer.write(text);
                        writer.write("]]>");
                    } else {
                        writer.write(text);
                    }
                }
            };
        }
    });

    /**
     * 文本消息对象转换成xml
     *
     * @param textMessage 文本消息对象
     * @return xml
     * 1.xstream的alias使用方法：
     * 1.1 作用：将序列化中的类全量名称，用别名替换(没有替换的属性,则原样输出)
     * 1.2  使用方法：xstream.alias("blog", Blog.class);
     *
     * 2.xstream的aliasField
     * 2.1 作用：使用别名替代属性名
     * 2.2 使用方法：xstream.aliasField("author", Author.class, "name");
     */
    public static String textMessageToXml(TextMessage textMessage) {
        xstream.alias("xml", textMessage.getClass());
//        xstream.alias("xml0", textMessage.getClass());
//        xstream.aliasField("funcFlag0", TextMessage.class, "funcFlag");
        return xstream.toXML(textMessage);
    }
}
